package mapspinner.util;

import com.jmex.effects.water.ImprovedNoise;
import com.jmex.terrain.util.AbstractHeightMap;

/**
 * PerlinHeightMap differentiates itself from the jme heightmap in that it can
 * create an adjacent, matching heightmap based on positional data given.
 * 
 * @author James Vos
 */
public class PerlinHeightMap extends AbstractHeightMap {
	private int offseti = 32, offsetj = 32;
	private float frequency = 0.000005f;
	private float strength = 500;
	private int iterations = 7;

	/**
	 * Creates this object
	 * 
	 * @param size
	 *            is the width and breadth of the map to generate
	 */
	public PerlinHeightMap(final int size) {
		this.size = size;
	}

	/**
	 * Generate the map and store it for retrieval.
	 * 
	 * @return is always true atm.
	 */
	@Override
	public boolean load() {
		heightData = new float[size * size];
		double tempVal = 0;
		float magicX = 0;
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++) {
				tempVal = 0;
				for (int x = 1; x <= iterations; x++) {
					magicX = x / 64f * x / 4f * x * 4f * x * 4096f;
					tempVal += ImprovedNoise.noise((i + offseti * (size - 1))
							* frequency * magicX, (j + offsetj * (size - 1))
							* frequency * magicX, 0)
							* strength / magicX;
				}
				setHeightAtPoint((float) tempVal, i, j);
			}
		return true;
	}

	/**
	 * sets the frequency, strength and iterations of the perlin heightmap
	 * 
	 * @param frequency
	 *            is the frequency of the noise
	 * @param strength
	 *            is the strength of the noise
	 * @iterations is how many levels deep this perlin noise calculates
	 */
	public void setGenerationValues(final float frequency,
			final float strength, final int iterations) {
		this.frequency = frequency / 100000f;
		this.strength = strength * 1000f;
		this.iterations = iterations;
	}

	/**
	 * Changes the offset of the map to generate, 0,1 would make an adjacent map
	 * to 0,0
	 * 
	 * @param offsetX
	 *            is the x offset
	 * @param offsetY
	 *            is the y offset
	 */
	public void setOffsets(final int offsetX, final int offsetY) {
		offseti = offsetX + 32;
		offsetj = offsetY + 32;
	}
}
